module Test
  module Unit
    class TestResult
      attr_reader :notifications

      alias_method(:initialize_without_notifications, :initialize)
      def initialize
        initialize_without_notifications
        @notifications = []
      end

      def add_notification(notification)
        @notifications << notification
        notify_listeners(FAULT, notification)
        notify_listeners(CHANGED, self)
      end

      def notification_count
        @notifications.size
      end

      alias_method(:to_s_without_notifications, :to_s)
      def to_s
        to_s_without_notifications + ", #{notification_count} notifications"
      end
    end

    class Notification
      include Util::BacktraceFilter
      attr_reader :test_name, :location, :message
      
      SINGLE_CHARACTER = 'N'

      # Creates a new Notification with the given location and
      # message.
      def initialize(test_name, location, message)
        @test_name = test_name
        @location = location
        @message = message
      end
      
      # Returns a single character representation of a notification.
      def single_character_display
        SINGLE_CHARACTER
      end

      # Returns a brief version of the error description.
      def short_display
        "#@test_name: #{@message.split("\n")[0]}"
      end

      # Returns a verbose version of the error description.
      def long_display
        location_display = filter_backtrace(location)[0]
        location_display = location_display.sub(/\A(.+:\d+).*/, ' [\\1]')
        "Notification:\n#{@test_name}#{location_display}:\n#{@message}"
      end

      # Overridden to return long_display.
      def to_s
        long_display
      end
    end

    class NotifiedError < StandardError
    end

    module AssertionsWithNotify
      def notify(message)
        notification = Notification.new(name, caller[0, 1], message)
        @_result.add_notification(notification)
      end
    end

    class TestCase
      include AssertionsWithNotify
    end
  end
end
